Pin calendar version when changesets bumps a major - #4607
Draft
andrewmcgov wants to merge 1 commit into
Draft
Conversation
`changeset version` feeds our changeset bump types straight into
`semver.inc()`. Because we use calendar versioning (`YYYY.MM.PATCH`), a
`major` bump always rolls the year:
semver.inc('2026.10.0-rc.1', 'major') -> '2027.0.0'
This is what produced `2027.0.0-rc.1` on the 2026-10-rc release PR (#4603)
and `2027.0.0-rc.1` on 2026-07-rc before it (#4290). Both times a human had
to hand-correct the versions, changelogs and pre.json before CI would pass.
Wrap `changeset version` so that after it runs we re-pin `YYYY.MM` and keep
whatever patch/prerelease counter changesets calculated. Bump types stay
purely changelog semantics, so release cuts can keep using `major`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
The
Version Packages (2026-10-rc)PR (#4603) landed with the version2027.0.0-rc.1instead of2026.10.0-rc.1.Root cause
We deliberately mark API-version cuts as
majorchangesets so the generated CHANGELOG reads "Major Changes". Butchangeset versionfeeds that bump type straight intosemver.inc(), and on a calendar version a semver major bump always rolls the year:node-semver has a "pre-major" shortcut that would keep
1.0.0-rc.0at1.0.0, but it only fires when minor and patch are both 0. Our minor is the month, so it never fires:This is not new. The same thing happened on
2026-07-rc(#4290) — the bot's commit produced2027.0.0-rc.1from2026.7.0-rc.0, and it only reached npm as2026.7.0-rc.1because it was hand-corrected in three follow-up commits ("lint fix", "update to correct versioning", "update extension tester example test to new api version"). It will recur on every RC branch that receives amajorchangeset.Note that only
majoris hazardous on an RC branch.minorandpatchare no-ops there, because node-semver leaves minor alone when patch is 0 and a prerelease is present — which is whyrc.2released cleanly off aminorchangeset.Left unfixed, the real risk isn't the red CI (that's loud and obvious) — it's that
2027.0.0-rc.1reaching npm would outrank every future2026.xrelease on thercdist-tag permanently, and npm versions can't be reused.Solution
In this repo
YYYY.MMis chosen by a human at RC-cut time. Changeset bump types are changelog semantics only and must never move it.So
scripts/changeset-version.mjswrapschangeset version: run it as normal, then re-pinYYYY.MMand keep whatever patch/prerelease counter changesets calculated.It then swaps the stale version across every
packages/*/package.jsonandCHANGELOG.md— covering package versions, internal dependency ranges, and changelog headings in one pass — and finishes withprettier --write .changeset/pre.json, which fixes the second CI failure permanently.It's wired in as the
versioninput ofchangesets/action, which defaults tochangeset version:semveris added as a root devDependency, pinned to^7.5.3so it reuses the resolution already inyarn.lock(no lockfile change, no duplicate copy innode_modules).How the release flow works now
Nothing changes about how you release. Each release is still two pushes to the version branch:
The script runs only at step 2, on the runner. It never runs on the publish leg, and never locally unless you invoke
yarn version:calendaryourself. In pre mode "unconsumed" means not yet listed inpre.json'schangesetsarray, which is why merging the Version Packages PR doesn't re-trigger versioning even though the.mdfiles remain on the branch.Deliberately unaffected:
/snapit,deploy:unstableanddeploy:internalall produce0.0.0-*snapshot versions where calendar pinning would be meaningless, so they bypass the wrapper.majorchangeset mid-RC2027.0.0-rc.32026.10.0-rc.3patchchangeset mid-RC2026.10.0-rc.3majoron a stable branch2027.0.02026.10.1(no collision with2026.10.0)Full CI gate green locally:
yarn build,yarn type-check,eslint . --max-warnings 0(on a pristine tree),prettier --check, tester typecheck + 75 tests, all 4 example suites,yarn docs:admin.